class SimpleVirtualScroll {
  constructor(container, itemCount, itemHeight, renderItem) {
    this.container = container;
    this.itemCount = itemCount;
    this.itemHeight = itemHeight;
    this.renderItem = renderItem;
    
    // 创建DOM结构
    this.scroller = document.createElement('div')
    this.scroller.style.height = '100%'
    this.scroller.style.overflow = 'auto'

    this.content = document.createElement('div')
    this.content.style.position = 'relative'
    this.content.style.height = `${this.itemCount * this.itemHeight}px`
    this.scroller.appendChild(this.content)

    this.container.appendChild(this.scroller)

    // 绑定事件
    this.scroller.addEventListener('scroll', () => this.handleScroll());
    
    // 初始渲染
    this.handleScroll();
  }
  handleScroll() {
    const scrollTop = this.scroller.scrollTop

    const startIndex = Math.floor(scrollTop / this.itemHeight)
    const endIndex = Math.min(
        this.itemCount - 1,
        startIndex + (Math.ceil(this.scroller.clientHeight / this.itemHeight))
    )
    // 清空内容
    this.content.innerHTML = ''

    // 渲染可见项目
    for (let i = startIndex; i <= endIndex; i ++) {
        const item = document.createElement('div');
        item.style.position = 'absolute';
        item.style.top = `${i * this.itemHeight}px`;
        item.style.height = `${this.itemHeight}px`;
        item.style.width = '100%';
        this.renderItem(item, i);
        this.content.appendChild(item)
    }
  }
}

class BufferedVirtualScroll extends SimpleVirtualScroll {
    constructor (container, itemCount, itemHeight, renderItem, bufferSize = 3) {
        super(container, itemCount, itemHeight, renderItem);
        this.bufferSize = bufferSize;
        this.pool = []; // DOM节点池

        // 初始渲染
        this.handleScroll();
    }
    handleScroll() {
        const scrollTop = this.scroller.scrollTop;
        const startIdx = Math.max(
            0,
            Math.floor(scrollTop / this.itemHeight) - this.bufferSize
        );
        const endIdx = Math.min(
            this.itemCount - 1,
            startIdx + Math.ceil(this.scroller.clientHeight / this.itemHeight) + this.bufferSize
        );
        // 回收不再使用的DOM节点
        const children = Array.from(this.content.children);
        children.forEach(child => {
            const idx = parseInt(child.dataset.index);
            if (idx < startIdx || idx > endIdx) {
                this.content.removeChild(child);
                this.pool.push(child); // 放入池中复用
            }
        })

        // 渲染新可见的项目
        for (let i = startIdx; i <= endIdx; i++) {
            // 检查是否已经存在
            if (this.content.querySelector(`[data-index="${i}"]`)) continue;
            // 从池中获取或创建新元素
            let item = this.pool.pop();
            if (!item) {
                item = document.createElement('div');
                item.style.position = 'absolute';
                item.style.height = `${this.itemHeight}px`;
                item.style.width = '100%';
            }
            item.style.top = `${i * this.itemHeight}px`;
            item.dataset.index = i;
            this.renderItem(item, i);
            this.content.appendChild(item);
        }
    }
}

class DynamicHeightVirtualScroll {
  constructor(options) {
    // 必需参数检查
    if (!options.container) throw new Error('必须提供container元素');
    if (typeof options.renderItem !== 'function') throw new Error('必须提供renderItem函数');
    
    // 配置参数
    this.container = options.container;
    this.itemCount = options.itemCount || 0;
    this.renderItem = options.renderItem;
    this.bufferSize = options.bufferSize || 5;
    
    // 状态变量
    this.itemPositions = []; // 每个项目的顶部位置
    this.itemHeights = [];   // 每个项目的实际高度
    this.estimatedHeight = options.estimatedHeight || 50; // 项目预估高度
    this.totalHeight = 0;    // 内容总高度
    this.pool = [];         // DOM节点池
    
    // 初始化
    this.initDOM();
    this.calculatePositions();
    this.bindEvents();
    this.render();
  }

  // 初始化DOM结构
  initDOM() {
    this.container.style.overflow = 'hidden';
    this.container.style.position = 'relative';
    
    this.scroller = document.createElement('div');
    this.scroller.style.width = '100%';
    this.scroller.style.height = '100%';
    this.scroller.style.overflow = 'auto';
    this.scroller.style.position = 'relative';
    
    this.content = document.createElement('div');
    this.content.style.position = 'relative';
    
    this.scroller.appendChild(this.content);
    this.container.appendChild(this.scroller);
  }

  // 计算所有项目的位置
  calculatePositions() {
    let position = 0;
    this.itemPositions = [];
    
    for (let i = 0; i < this.itemCount; i++) {
      this.itemPositions[i] = position;
      position += this.itemHeights[i] || this.estimatedHeight;
    }
    
    this.totalHeight = position;
    this.content.style.height = `${this.totalHeight}px`;
    console.log('this.itemPositions', this.itemPositions)
  }

  // 绑定事件
  bindEvents() {
    this.scroller.addEventListener('scroll', () => {
      this.render();
    });
    
    // 使用ResizeObserver监听容器大小变化
    if (typeof ResizeObserver !== 'undefined') {
      this.resizeObserver = new ResizeObserver(() => {
        this.render();
      });
      this.resizeObserver.observe(this.container);
    }
  }

  // 渲染可见项目
  render() {
    const scrollTop = this.scroller.scrollTop;
    const viewportHeight = this.scroller.clientHeight;
    
    // 使用二分查找确定可见范围
    const startIdx = this.findNearestItem(scrollTop);
    const endIdx = this.findNearestItem(scrollTop + viewportHeight);

    // 应用缓冲区
    const renderStart = Math.max(0, startIdx - this.bufferSize);
    const renderEnd = Math.min(this.itemCount - 1, endIdx + this.bufferSize);
    
    // 回收不可见的DOM节点
    this.recycleItems(renderStart, renderEnd);
    
    // 渲染可见项目
    for (let i = renderStart; i <= renderEnd; i++) {
      this.renderItemAt(i);
    }
  }

  // 二分查找定位项目
  findNearestItem(position) {
    let low = 0;
    let high = this.itemCount - 1;
    let mid;
    let midPos;
    
    while (low <= high) {
      mid = Math.floor((low + high) / 2);
      midPos = this.itemPositions[mid];
      
      if (midPos === position) {
        return mid;
      } else if (midPos < position) {
        low = mid + 1;
      } else {
        high = mid - 1;
      }
    }
    
    return low > 0 ? low - 1 : 0;
  }

  // 回收不可见的项目
  recycleItems(renderStart, renderEnd) {
    const itemsToRemove = [];
    
    // 收集需要回收的项目
    Array.from(this.content.children).forEach(item => {
      const index = parseInt(item.dataset.index);
      if (index < renderStart || index > renderEnd) {
        itemsToRemove.push(item);
      }
    });
    
    // 移出DOM并放入池中
    itemsToRemove.forEach(item => {
      this.content.removeChild(item);
      this.pool.push(item);
    });
  }

  // 渲染单个项目
  renderItemAt(index) {
    // 如果已经渲染则跳过
    if (this.content.querySelector(`[data-index="${index}"]`)) return;
    
    // 从池中获取或创建新元素
    let item = this.pool.pop() || document.createElement('div');
    item.style.position = 'absolute';
    item.style.width = '100%';
    item.dataset.index = index;
    
    // 渲染项目内容
    this.renderItem(item, index);
    
    // 设置位置
    item.style.top = `${this.itemPositions[index]}px`;
    this.content.appendChild(item);
    
    // 测量实际高度
    this.measureItemHeight(index, item);
  }

  // 测量项目高度并更新布局
  measureItemHeight(index, item) {
    const oldHeight = this.itemHeights[index];
    const newHeight = item.offsetHeight;
    
    // 如果高度发生变化
    if (oldHeight !== newHeight) {
      this.itemHeights[index] = newHeight;
      
      // 更新平均高度估算
      const measuredCount = this.itemHeights.filter(h => h > 0).length;
      if (measuredCount > 0) {
        const sum = this.itemHeights.reduce((s, h) => s + (h || 0), 0);
        this.estimatedHeight = sum / measuredCount;
      }
      
      // 重新计算所有位置
      this.calculatePositions();
      
      // 需要重新渲染
      this.render();
    }
  }

  // 更新数据
  update(newCount) {
    this.itemCount = newCount;
    this.calculatePositions();
    this.render();
  }

  // 滚动到指定项目
  scrollToIndex(index, behavior = 'auto') {
    const position = this.itemPositions[index];
    this.scroller.scrollTo({
      top: position,
      behavior
    });
  }

  // 销毁
  destroy() {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
    }
    this.scroller.removeEventListener('scroll', this.render);
    this.container.removeChild(this.scroller);
  }
}